﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PMP
{
    public class PlayList<TMusicFile>: IPlayList<TMusicFile, PlayList<TMusicFile>.DefaultPlayModes> where TMusicFile: class
    {
        public enum DefaultPlayModes { CurrentOnce, CurrentRepeat, AllOnce, AllRepeat, AllRandomOnce, AllRandomRepeat }

        public PlayList()
            : this(new List<TMusicFile>())
        {
        }

        public PlayList(IEnumerable<TMusicFile> musicFiles)
        {
            _Contents = new List<TMusicFile>();
            _Contents.AddRange(musicFiles);
            HasBeenPlayed = new List<TMusicFile>();
            HasNotBeenPlayedYet = new List<TMusicFile>();
            ThisPlayList = new List<TMusicFile>();
            CurrentFile_Int = 0;
        }

        #region Privates
        private string _Name;
        private DefaultPlayModes _PlayMode;
        private int _CurrentFile_Int;
        private int _CurrentFile_Int_Repeat;

        private List<TMusicFile> _Contents { get; set; }
        private List<TMusicFile> HasBeenPlayed { get; set; }
        private List<TMusicFile> HasNotBeenPlayedYet { get; set; }
        private List<TMusicFile> ThisPlayList { get; set; }
        private int CurrentFile_Int
        {
            get { return _CurrentFile_Int; }
            set
            {
                if (value < 0 || value > Contents.Count())
                {
                    throw new ArgumentOutOfRangeException();
                }
                _CurrentFile_Int = value;
            }
        }
        private int CurrentFile_Int_Repeat
        {
            get { return CurrentFile_Int; }
            set
            {
                CurrentFile_Int = (value > Contents.Count()
                    ? 0
                    : value);
            }
        }
        #endregion

        private List<TMusicFile> Shuffle(IEnumerable<TMusicFile> toShuffle_in)
        {
            var shuffled = new List<TMusicFile>();
            var toShuffle = toShuffle_in.ToList();

            while (toShuffle.Count > 0)
            {
                int get = new Random().Next(0, toShuffle.Count);

                shuffled.Add(toShuffle[get]);
                toShuffle.RemoveAt(get);
            }

            return shuffled;
        }

        private bool Repeating(DefaultPlayModes playmode)
        {
            return (
                playmode == DefaultPlayModes.AllRandomRepeat
                || playmode == DefaultPlayModes.AllRepeat
                || playmode == DefaultPlayModes.CurrentRepeat)
                ? true : false;
        }

        #region IPlayList<TMusicFile,DefaultPlayModes> Members

        public string Name
        {
            get { return _Name; }
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    throw new ArgumentException();
                }
                _Name = value;
            }
        }

        public IEnumerable<TMusicFile> Contents
        {
            get { return _Contents.AsEnumerable(); }
        }

        public PlayList<TMusicFile>.DefaultPlayModes PlayMode
        {
            get { return _PlayMode; }
            set
            {
                HasBeenPlayed.Clear();
                HasNotBeenPlayedYet = Contents.ToList();
                ThisPlayList.Clear();

                if (value == DefaultPlayModes.CurrentRepeat || value == DefaultPlayModes.CurrentOnce)
                {
                    ThisPlayList.Add(CurrentFile);
                }
                else
                {
                    ThisPlayList = Contents.ToList();
                }

                _PlayMode = value;
            }
        }

        public IEnumerable<TMusicFile> ApplyPlayModeAndGetPlayList
        {
            get { return ThisPlayList; }
        }

        public TMusicFile CurrentFile
        {
            get { return Contents.ElementAt(CurrentFile_Int); }
            set
            {
                CurrentFile_Int = Contents.ToList().IndexOf(value);
            }
        }

        public TMusicFile NextFileInCurrentPlayList
        {
            get
            {
                TMusicFile toReturn = default(TMusicFile);

                switch (PlayMode)
                {
                    case DefaultPlayModes.CurrentOnce:
                        if (HasBeenPlayed.Count == 0)
                        {
                            toReturn = CurrentFile;
                            HasBeenPlayed.Add(CurrentFile);
                        }
                        else if (HasBeenPlayed.Count > 2)
                        {
                            throw new Exception("How did we end up here? Currently for testing");
                        }
                        break;


                    case DefaultPlayModes.CurrentRepeat:
                        toReturn = CurrentFile;
                        break;

                    case DefaultPlayModes.AllOnce:
                        if (HasNotBeenPlayedYet.Count > 0)
                        {
                            toReturn = HasNotBeenPlayedYet[0];
                            HasBeenPlayed.Add(toReturn);
                            HasNotBeenPlayedYet.RemoveAt(0);
                        }
                        break;

                    case DefaultPlayModes.AllRepeat:
                        CurrentFile_Int_Repeat++;
                        toReturn = CurrentFile;
                        break;

                    case DefaultPlayModes.AllRandomOnce:
                        if (HasNotBeenPlayedYet.Count > 0)
                        {
                            int val = new Random().Next(0, HasNotBeenPlayedYet.Count);
                            toReturn = HasNotBeenPlayedYet[val];
                            HasBeenPlayed.Add(toReturn);
                            HasNotBeenPlayedYet.RemoveAt(val);
                        }
                        break;

                    case DefaultPlayModes.AllRandomRepeat:
                        toReturn = ThisPlayList[new Random().Next(0, ThisPlayList.Count)];
                        break;

                    default:
                        throw new Exception();
                        break;
                }

                return toReturn;
            }
        }

        #endregion
    }
}
